package edu.gmu;

import java.util.List;
import java.util.LinkedList;

/**
 * Stack holds token/node values while the syntax parse tree is being created
 * from the productions.
 * User: james
 * Date: 3/9/11
 * Time: 3:59 PM
 * To change this template use File | Settings | File Templates.
 */
public class Stack
{
//    jamess-macbook-pro:Minidl james$ java -cp ./dist/minidl.jar IDLParser Event.idl
//    IDL Parser Version 0.1:  Reading from file Event.idl . . .
//      specification
//        definition
//          module
//            identifier
//            definition
//              interfacex
//                interface_dcl
//                  interface_header
//                    identifier
//                  interface_body
//                    export
//                      attr_dcl
//                        param_type_spec
//                          scoped_name
//                            identifier
//                        simple_declarator
//                          identifier
//                    export
//                      attr_dcl
//                        param_type_spec
//                          string_type
//                        simple_declarator
//                          identifier
//    IDL Parser Version 0.1:  IDL definitions parsed successfully.



    private List stack = new LinkedList();

    /**
     * Creates a new Stack with default values.
     */
    public Stack()
    {

    }

    /**
     * Returns value at top of the stack without removing.
     * @return top item or null if no items on stack
     */
    public ASTNode peek()
    {
        if( this.stack.size() == 0 )
        {
            return null;
        }
        return (ASTNode)this.stack.get( stack.size()-1 );
    }

    /**
     * Returns value at top of the stack and removes at same time.
     * Also sets the mark of the node to -1 asw it is no longer
     * in the stack.
     * @return removed item
     */
    public ASTNode pop()
    {
        ASTNode removedNode = (ASTNode)this.stack.remove( stack.size()-1 );
        removedNode.setMark(-1);
        return removedNode;
    }

    /**
     * Pushes the specified item to the top of the stack.  Sets the mark
     * in the stack on the specified item itself and returns the mark.
     * @return mark (index) of item in stack
     */
    public int push( ASTNode item )
    {
        this.stack.add( item );
        int mark = this.stack.size();
        item.setMark( mark );
        return mark;
    }

    /**
     * Returns size of the stack.
     * @return size
     */
    public int getSize()
    {
        return this.stack.size();
    }

    /**
     * Pops off all items after mark and puts into returned list.
     * After a successful call, the item at mark is the top.
     * @param mark
     * @return list of children (size = stack.size - mark)
     */
    public List popChildren( int mark )
    {
        List children = new LinkedList();
        int numChildren = this.stack.size() - mark;

        // Sanity check
        if( numChildren < 0 || numChildren > this.stack.size() )
        {
            String s = "Invalid params for popChildren: mark=" +
                    mark + " stack.size=" + this.stack.size();
            throw new IllegalArgumentException(s);
        }

        int i = 0;
        while( i < numChildren )
        {
            Object child = this.pop();
            children.add(child);
            i++;
        }
        return children;
    }

    /**
     * String version of this object
     * @return string
     */
    public String toString()
    {
        StringBuffer buf = new StringBuffer();
        for( int i = 0; i < this.stack.size(); i++ )
        {
            buf.append( "["+i+"]="+this.stack.get(i) );
        }
        return buf.toString();
    }

}
